﻿using log4net;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading.Tasks;
using System.Timers;

namespace HobSoft.SoccerBet2014.Server.SiteManagerSchedule
{
    using Configuration;
    using Domain.Common.Factory;
    using Domain.Common.Site;
    using Domain.Models;
    public class SiteManagerSchedule
    {
        private readonly Timer siteScheduleTimer;
        private readonly ISiteManagerFactory factory;
        private ConcurrentDictionary<string, SiteManagerView> siteManagers;
        private Bookmaker SiteBookmaker;
        private BmsConfiguration Setting;
        public event EventHandler<SiteManagerView> OnManagerAdded;
        public event EventHandler<SiteManagerView> OnManagerRemoved;
        public event EventHandler<byte> OnManagerClear;
        private ILog infoLoger = LogManager.GetLogger("ApplicationCacheLog");
        protected virtual void RaiseOnManagerClear()
        {
            if (OnManagerClear != null)
                OnManagerClear(this, SiteBookmaker.BmID);
        }
        protected virtual void RaiseOnManagerAdded(SiteManagerView newManager)
        {
            if (OnManagerAdded != null)
                OnManagerAdded(this, newManager);
        }
        protected virtual void RaiseOnManagerRemoved(SiteManagerView removeManager)
        {
            if (OnManagerRemoved != null)
                OnManagerRemoved(this, removeManager);
        }


        private SiteManagerSchedule() { }
        public SiteManagerSchedule(ISiteManagerFactory fact)
        {
            factory = fact;

            siteManagers = new ConcurrentDictionary<string, SiteManagerView>();
            siteScheduleTimer = new Timer();
        }
        public void Initialize(Bookmaker siteBookmaker, BmsConfiguration setting)
        {
            SiteBookmaker = siteBookmaker;
            Setting = setting;

            siteManagers.Clear();
            RaiseOnManagerClear();

            siteScheduleTimer.Interval = setting.TimerInterval;
            siteScheduleTimer.Elapsed += ScheduleTimer_Elapsed;
            foreach (var account in siteBookmaker.Accounts)
            {
                if (!account.Available) continue;
                SiteManagerView siteManagerState;
                if (!siteManagers.TryGetValue(account.Account, out siteManagerState))
                {
                    SessionManagerBase siteManager = factory.Create(siteBookmaker.BmID, account.Account, siteBookmaker.DefaultHost);
                    if (siteManager != null)
                    {
                        siteManagerState = new SiteManagerView(siteBookmaker.BmID, account.Account, account.Password, siteManager);
                        siteManagers.TryAdd(account.Account, siteManagerState);
                        RaiseOnManagerAdded(siteManagerState);
                    }
                }
            }
        }
        public void Start()
        {
            var query = siteManagers.Values.Where(s => s.OnSignup);
            Task<Task<bool>>[] tasks = new Task<Task<bool>>[query.Count()];
            int index = 0;
            foreach (var smanager in query)
            {
                tasks[index] = Task.Factory.StartNew(() => smanager.RequestEarly());
            }
            if (tasks.Any())
            {
                Task.WaitAll(tasks);
                siteScheduleTimer.Start();
            }
        }

        public void Signup()
        {
            Task<Task<bool>>[] tasks = new Task<Task<bool>>[siteManagers.Count];
            int index = 0;
            foreach (var smg in siteManagers)
            {
                
                tasks[index] = Task.Factory.StartNew(() => smg.Value.Signup());
                tasks[index].ContinueWith(t =>
                {
                    if (t.IsCanceled || t.Exception != null)
                    {
                        if (infoLoger != null)
                            infoLoger.WarnFormat("【{1}】{0}登陆失败，请求发生错误。", smg.Value.Account, SiteBookmaker.BmName);
                    }
                    if (infoLoger != null)
                    {
                        if (t.Result.Result)
                            infoLoger.InfoFormat("【{1}】{0}登陆成功。", smg.Value.Account, SiteBookmaker.BmName);
                        else
                            infoLoger.InfoFormat("【{1}】{0}登陆失败。", smg.Value.Account, SiteBookmaker.BmName);
                    }
                });
                index++;
            }
            Task.WaitAll(tasks);
        }

        protected virtual void ScheduleTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            var minTime = siteManagers.Where(s => s.Value.OnSignup).Min(m => m.Value.LastLiveRequest);
            var manager = siteManagers.Where(s => s.Value.OnSignup).FirstOrDefault(m => m.Value.LastLiveRequest == minTime);
            if (manager.Value == null) return;

            var liveSpan = DateTime.Now - minTime;
            var todaySpan = DateTime.Now - manager.Value.LastTodayRequest;

            if ((liveSpan == null || !liveSpan.HasValue) && (todaySpan == null || !todaySpan.HasValue))
            {
                if (infoLoger != null)
                    infoLoger.InfoFormat("【{1}】{0}开始刷新滚球、赛前数据。", manager.Value.Account, SiteBookmaker.BmName);
                manager.Value.RequestReady().ContinueWith(t =>
                {
                    if (t.IsCanceled || t.Exception != null) return;
                    manager.Value.RequestFullLive().ContinueWith(rlt =>
                    {
                        if (rlt.Result && infoLoger != null)
                            infoLoger.InfoFormat("【{1}】{0}更新滚球数据完成。", manager.Value.Account, SiteBookmaker.BmName);
                    });
                    manager.Value.RequestFullToday().ContinueWith(rtt =>
                    {
                        if (rtt.Result && infoLoger != null)
                            infoLoger.InfoFormat("【{1}】{0}更新今日赛前数据完成。", manager.Value.Account, SiteBookmaker.BmName);
                    });
                });
                return;
            }
            if (liveSpan.HasValue && todaySpan.HasValue
                && liveSpan.Value.TotalSeconds > Setting.LiveResetInterval
                && todaySpan.Value.TotalSeconds > Setting.TodayResetInterval)
            {
                if (infoLoger != null)
                    infoLoger.InfoFormat("【{1}】{0}开始刷新滚球、赛前数据。", manager.Value.Account, SiteBookmaker.BmName);
                manager.Value.RequestReady().ContinueWith(t =>
                {
                    if (t.IsCanceled || t.Exception != null) return;
                    manager.Value.RequestFullLive().ContinueWith(rlt =>
                    {
                        if (rlt.Result && infoLoger != null)
                            infoLoger.InfoFormat("【{1}】{0}更新滚球数据完成。", manager.Value.Account, SiteBookmaker.BmName);
                    });
                    manager.Value.RequestFullToday().ContinueWith(rtt =>
                    {
                        if (rtt.Result && infoLoger != null)
                            infoLoger.InfoFormat("【{1}】{0}更新今日赛前数据完成。", manager.Value.Account, SiteBookmaker.BmName);
                    });
                });
                return;
            }

            if (liveSpan == null || !liveSpan.HasValue || (liveSpan.HasValue && liveSpan.Value.TotalSeconds > Setting.LiveResetInterval))
            {
                if (infoLoger != null)
                    infoLoger.InfoFormat("【{1}】{0}开始刷新滚球数据。", manager.Value.Account, SiteBookmaker.BmName);
                manager.Value.RequestFullLive().ContinueWith(rlt =>
                {
                    if (rlt.Result && infoLoger != null)
                        infoLoger.InfoFormat("【{1}】{0}更新滚球数据完成。", manager.Value.Account, SiteBookmaker.BmName);
                });
            }
            else if (liveSpan.Value.TotalSeconds > Setting.LiveCountdown)
            {
                if (infoLoger != null)
                    infoLoger.InfoFormat("【{1}】{0}开始刷新滚球数据。", manager.Value.Account, SiteBookmaker.BmName);
                manager.Value.UpdateLive().ContinueWith(rlt =>
                {
                    if (rlt.Result && infoLoger != null)
                        infoLoger.InfoFormat("【{1}】{0}更新滚球数据完成。", manager.Value.Account, SiteBookmaker.BmName);
                });
            }

            if (todaySpan == null || !todaySpan.HasValue || (todaySpan.HasValue && todaySpan.Value.TotalSeconds > Setting.TodayResetInterval))
            {
                if (infoLoger != null)
                    infoLoger.InfoFormat("【{1}】{0}开始刷新赛前数据。", manager.Value.Account, SiteBookmaker.BmName);
                manager.Value.RequestFullToday().ContinueWith(rtt =>
                {
                    if (rtt.Result && infoLoger != null)
                        infoLoger.InfoFormat("【{1}】{0}更新今日赛前数据完成。", manager.Value.Account, SiteBookmaker.BmName);
                });
            }
            else if (todaySpan.Value.TotalSeconds > Setting.TodayCountdown)
            {
                if (infoLoger != null)
                    infoLoger.InfoFormat("【{1}】{0}开始刷新赛前数据。", manager.Value.Account, SiteBookmaker.BmName);
                manager.Value.UpdateToday().ContinueWith(rtt =>
                {
                    if (rtt.Result && infoLoger != null)
                        infoLoger.InfoFormat("【{1}】{0}更新今日赛前数据完成。", manager.Value.Account, SiteBookmaker.BmName);
                });
            }
        }
    }
}
